﻿//using MODI;
using Nop.Core;
using Nop.Core.Data;
using Nop.Core.Domain.WindAlert;
using Nop.Data;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;

namespace Nop.Services.WindAlert
{
    /// <summary>
    /// Winddata service
    /// </summary>
    public partial class WindDataService : IWindDataService
    {
        #region Fields

        private readonly IRepository<WindData> _windDataRepository;
        private readonly IDbContext _dbContext;
        private readonly IWindHelpers _windHelper;
        #endregion

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="windDataRepository">Live Station repository</param>
        public WindDataService(IRepository<WindData> windDataRepository,
            IDbContext dbContext, IWindHelpers windHelper)
        {
            this._windDataRepository = windDataRepository;
            this._dbContext = dbContext;
            this._windHelper = windHelper;
        }
        #endregion

        #region WindData Methods

        /// <summary>
        /// Clears a data
        /// </summary>
        public virtual void ClearAll()
        {
            var windData = _windDataRepository.Table.ToList();
            foreach (var wdItem in windData)
                _windDataRepository.Delete(wdItem);
            //setIdentity();
        }

        /// <summary>
        /// Deletes a windData
        /// </summary>
        /// <param name="windData">WindData</param>
        public virtual void DeleteWindData(WindData windData)
        {
            if (windData == null)
                throw new ArgumentNullException("windData");

            _windDataRepository.Delete(windData);
        }

        /// <summary>
        /// Gets all windDatas
        /// </summary>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <param name="windDataId">Station Id</param>
        /// <returns>Station collection</returns>
        public virtual IList<WindData> GetAllWindData()
        {
                var query = from m in _windDataRepository.Table
                            select m;
                var windDatas = query.ToList();
                return windDatas;
        }

        /// <summary>
        /// Gets all windDatas
        /// </summary>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <param name="showHidden">A value indicating whether to show hidden records</param>
        /// <param name="windDataId">Station Id</param>
        /// <returns>Stations</returns>
        public virtual IPagedList<WindData> GetAllWindData(int pageIndex, int pageSize)
        {
            var windDatas = GetAllWindData();
            return new PagedList<WindData>(windDatas, pageIndex, pageSize);
        }


        /// <summary>
        /// Gets all winddata items
        /// </summary>
        /// <param name="fromUtc">windata item creation from; null to load all records</param>
        /// <param name="toUtc">windata item creation to; null to load all records</param>
        /// <param name="message">Message</param>
        /// <param name="pageIndex">Page index</param>
        /// <param name="pageSize">Page size</param>
        /// <returns>winddata item collection</returns>
        public virtual IPagedList<WindData> GetAllWindData(DateTime? fromUtc, DateTime? toUtc, int pageIndex, int pageSize)
        {
            var query = _windDataRepository.Table;
            if (fromUtc.HasValue)
                query = query.Where(wd => fromUtc.Value <= wd.CreatedOnUtc);
            if (toUtc.HasValue)
                query = query.Where(wd => toUtc.Value >= wd.CreatedOnUtc);
            
            query = query.OrderByDescending(wd => wd.Id);
           // query = query.OrderByDescending(wd => wd.CreatedOnUtc);

            var windData = new PagedList<WindData>(query, pageIndex, pageSize);
            return windData;
        }

        /// <summary>
        /// Gets a windData
        /// </summary>
        /// <param name="windDataId">Station identifier</param>
        /// <returns>Station</returns>
        public virtual WindData GetWindDataById(int windDataId)
        {
            if (windDataId == 0)
                return null;
            var windData = _windDataRepository.GetById(windDataId);
            return windData;
        }

        /// <summary>
        /// Get wind data items by identifiers
        /// </summary>
        /// <param name="windataIds">winddata item identifiers</param>
        /// <returns>Winddata items</returns>
        public virtual IList<WindData> GetWindDataByIds(int[] windaDataIds)
        {
            if (windaDataIds == null || windaDataIds.Length == 0)
                return new List<WindData>();

            var query = from wd in _windDataRepository.Table
                        where windaDataIds.Contains(wd.Id)
                        select wd;
            var windDataItems = query.ToList();
            //sort by passed identifiers
            var sortedWindDataItems = new List<WindData>();
            foreach (int id in windaDataIds)
            {
                var windData = windDataItems.Find(x => x.Id == id);
                if (windData != null)
                    sortedWindDataItems.Add(windData);
            }
            return sortedWindDataItems;
        }

        /// <summary>
        /// Get wind data itemby station Id
        /// </summary>
        /// <param name="StationIds">wind station identifiers</param>
        /// <returns>Winddata items</returns>
        public virtual IList<WindData> GetWindDataBySpotId(int spotId, int backHours=0)
        {
            if (spotId < 1)
                return new List<WindData>();

            var query = from wd in _windDataRepository.Table
                        where wd.SpotId == spotId
                        select wd;

            if(backHours != 0)
            {
                var compareDate = DateTime.Now.AddHours(backHours);
                query = from wd in query
                        where wd.StationAdjustedTime > compareDate
                        select wd;
            }
            var windDataItems = query.ToList();
            return windDataItems;
        }

        /// <summary>
        /// Get wind data item by station Id top 1
        /// </summary>
        /// <param name="StationIds">wind station identifiers</param>
        /// <returns>Winddata items</returns>
        public virtual WindData GetWindDataBySpotIdTop1(int spotId)
        {
            if (spotId <= 0)
                return new WindData();

            var query = (from wd in _windDataRepository.Table
                        where wd.SpotId == spotId
                        select wd).OrderByDescending(wd => wd.Id).FirstOrDefault();
            return query;
        }

        /// <summary>
        /// Inserts a windData
        /// </summary>
        /// <param name="windData">Wind data</param>
        public virtual void InsertWindData(WindData windData)
        {
            if (windData == null)
                throw new ArgumentNullException("windData");

            _windDataRepository.Insert(windData);
        }

        #endregion

        #region update station

        public virtual WindData UpdateStation(Spot spot)
        {
            string dataRow = "";
            //check it image or text
            var r = new Regex(@"[^\s]+(\.(?i)(jpg|png|gif|bmp))");
            var match = r.Match(spot.StationDataUrl);
            if (match.Success)
                dataRow = _windHelper.GetPageDataFromImage(spot.StationDataUrl);
            else
                dataRow = _windHelper.GetPageData(spot.StationDataUrl);

            if (string.IsNullOrEmpty(dataRow))
                dataRow = "1/1/12 * 0:00 * N * 0 * 0 * 0 * 0 * 0 * 0 * 0 * 0";
            var stationData = new WindData();
            switch (spot.StationSplitMethod)
            {
                case 1:
                    stationData = splitAllEx(spot.StationAdjustTime, dataRow);
                    break;
                case 10:
                    stationData = SplitLagunaData(spot.StationAdjustTime, dataRow);
                    break;
                case 20:
                    stationData = splitMetars(spot.StationAdjustTime, dataRow);
                    break;
                case 30:
                    stationData = SplitWindDetailsPage(spot.StationAdjustTime, dataRow);
                    break;
                case 40:
                    stationData = SplitIsramarImage(spot.StationAdjustTime, dataRow);
                    break;
                case 50: //Guru
                    stationData = SplitWindGuru(spot.StationAdjustTime, dataRow);
                    break;
                default:
                    stationData = splitAllEx(spot.StationAdjustTime, dataRow);
                    break;
            }
            stationData.SpotId = spot.Id;
            stationData.CreatedOnUtc = DateTime.Now;
            return stationData;
        }
        #endregion

        #region Split methods

        private WindData SplitWindGuru(int intAddHour, string strAllData)
        {

            var stationData = new WindData();
            try
            {
                if (strAllData == "Error") throw new NullReferenceException();
                string[] arrAll = strAllData.Split(',');
                //date
                var strTemp = Regex.Split(arrAll[7], "\"datetime\":\""); 
                strTemp[1] = strTemp[1].Remove(strTemp[1].Length - 4);
                //strTemp[1] = Regex.Replace(strTemp[1], "[A-Za-z ]", "");

                Thread.CurrentThread.CurrentCulture = new CultureInfo("he-IL");
                DateTime dateTemp = Convert.ToDateTime(strTemp[1]);
                stationData.StationTime = dateTemp;
                stationData.StationAdjustedTime = dateTemp.AddHours(intAddHour);
                //wind speed agv
                strTemp = arrAll[0].Split(':');
                stationData.WindSpeedAgv =Convert.ToInt32(double.Parse(strTemp[1]));
                //wind Gust
                strTemp = arrAll[1].Split(':');
                stationData.WindGust = Convert.ToInt32(double.Parse(strTemp[1]));
                //wind speed
                strTemp = arrAll[2].Split(':');
                stationData.WindSpeed = Convert.ToInt32(double.Parse(strTemp[1]));
                //direction
                strTemp = arrAll[3].Split(':');
                stationData.WindDirection = Convert.ToInt32(double.Parse(strTemp[1]));
                //temperture
                strTemp = arrAll[4].Split(':');
                stationData.Temperture = Convert.ToInt32(double.Parse(strTemp[1]));

                stationData.Humidity = 0;
                stationData.Barometer = 0;
                stationData.DewPoint = 0;
                stationData.CloudBase = 0;
            }
            catch (Exception ex)
            {
                string t = ex.Message;
                throw new NullReferenceException();
            }
            return stationData;

        }

        private WindData SplitIsramarImage(int intAddHour, string strAllData)
        {
            var WindDataStation = new WindData();
            try
            {
                if (strAllData == "Error") throw new NullReferenceException();
                string[] stringSeparators = new string[] { "Wind Measurement at" };
                string[] arrAll = strAllData.Split(stringSeparators, StringSplitOptions.None);

                // get date
                stringSeparators = new string[] { "Wind Speed is" };
                string[] arrTmp = arrAll[1].Split(stringSeparators, StringSplitOptions.None); 

                string tmpDate = arrTmp[0];

                Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
                DateTime dateTemp = Convert.ToDateTime(tmpDate);
                WindDataStation.StationTime = dateTemp;
                WindDataStation.StationAdjustedTime = dateTemp.AddHours(intAddHour);
                WindDataStation.CreatedOnUtc = dateTemp;

                // speed
                stringSeparators = new string[] { "or" };
                string[] arrTmpSpeed = arrTmp[1].Split(stringSeparators, StringSplitOptions.None);
                stringSeparators = new string[] { "(KNOT)" };
                string[] arrTmpSpeed1 = arrTmpSpeed[1].Split(stringSeparators, StringSplitOptions.None);
                double speedTmp = Convert.ToDouble(arrTmpSpeed1[0]);
                speedTmp = Math.Round(speedTmp, MidpointRounding.AwayFromZero);
                int speedTmpInt = Convert.ToInt32(speedTmp);

                WindDataStation.WindSpeed = speedTmpInt;
                WindDataStation.WindGust = Convert.ToInt32(speedTmpInt * 1.2);
                WindDataStation.WindSpeedAgv = speedTmpInt;

                //direction 
                stringSeparators = new string[] { "Direction is" };
                string[] arrDirTmp = arrTmpSpeed1[1].Split(stringSeparators, StringSplitOptions.None);

                stringSeparators = new string[] { "(degree)" };
                string[] arrDirTmp1 = arrDirTmp[1].Split(stringSeparators, StringSplitOptions.None);
                int dirTemp = Convert.ToInt32(Convert.ToDouble(arrDirTmp1[0]));
                WindDataStation.WindDirection = dirTemp;

            }
            catch (Exception ex)
            {
                string t = ex.Message;
            }
            return WindDataStation;
        }
        private WindData splitMetars(int addHoours, string strAllData)
        {
            var stationData = new WindData();
            try
            {
                int windDirection= 0;
                if (strAllData == "Error") throw new NullReferenceException();
                string[] arrAll = strAllData.Split(' ');
                string tmpTime = arrAll[1].Substring(0, 5);
                stationData.StationTime = Convert.ToDateTime(arrAll[0] + " " + tmpTime);
                stationData.StationAdjustedTime = stationData.StationTime.AddHours(addHoours);
                // direction
                if (int.TryParse(arrAll[3].Substring(0, 3), out windDirection))
                    stationData.WindDirection = windDirection;
                else
                    stationData.WindDirection = 0;
                //speed
                stationData.WindSpeed = int.Parse(arrAll[3].Substring(3, 2));
                stationData.WindGust = Convert.ToInt32(stationData.WindSpeed * 1.2);
                stationData.WindSpeedAgv = stationData.WindSpeed;
                string tmpBar;
                if (arrAll.Length == 9)
                {
                    stationData.Temperture = Convert.ToDouble(arrAll[6].Substring(0, 2));
                    tmpBar = arrAll[7];
                    stationData.Barometer = Convert.ToDouble(tmpBar.Substring(tmpBar.Length - 4, 4));
                }
                else if (arrAll.Length == 8)
                {
                    stationData.Temperture = Convert.ToDouble(arrAll[6].Substring(0, 2));
                    tmpBar = arrAll[7];
                    stationData.Barometer = Convert.ToDouble(tmpBar.Substring(tmpBar.Length - 5, 4));
                }
                else
                {
                    stationData.Temperture = Convert.ToDouble(arrAll[5].Substring(0, 2));
                    tmpBar = arrAll[6];
                    stationData.Barometer = Convert.ToDouble(tmpBar.Substring(tmpBar.Length - 5, 4));
                }
                stationData.Humidity = 0;
                stationData.CloudBase = 0; stationData.DewPoint = 0;

            }

            catch (Exception ex)
            {
                string t = ex.Message;
            }
            return stationData;
        }

        private WindData splitAllEx(int intAddHour, string strAllData)
        {

            var stationData = new WindData();
            try
            {
                if (strAllData == "Error") throw new NullReferenceException();

                string tmpDirectionL;
                string[] arrAll = strAllData.Split('*');
                Thread.CurrentThread.CurrentCulture = new CultureInfo("he-IL");
                DateTime dateTemp = Convert.ToDateTime(arrAll[0] + " " + arrAll[1]);
                stationData.StationTime = dateTemp;
                stationData.StationAdjustedTime = dateTemp.AddHours(intAddHour);
                tmpDirectionL = arrAll[2].Trim();
                stationData.WindSpeedAgv = int.Parse(arrAll[6]);
                stationData.WindSpeed = int.Parse(arrAll[3]);
                stationData.WindGust = int.Parse(arrAll[4]);
                stationData.WindDirection = _windHelper.getDirectionLettersToNum(tmpDirectionL);

                stationData.Temperture = Convert.ToDouble(arrAll[5]);
                // check all file
                if (arrAll.Length > 8)
                {
                    stationData.Humidity = Convert.ToDouble(arrAll[8]);
                    stationData.Barometer = Convert.ToDouble(arrAll[7]);
                    stationData.DewPoint = Convert.ToDouble(arrAll[9]);
                    stationData.CloudBase = Convert.ToDouble(arrAll[10]);
                }
                else
                {
                    stationData.Humidity = 0;
                    stationData.Barometer = 0;
                    stationData.DewPoint = 0;
                    stationData.CloudBase = 0;
                }
            }
            catch (Exception ex)
            {
                string t = ex.Message;
                throw new NullReferenceException();
            }
            return stationData;

        }

        private WindData SplitLagunaData(int intAddHour, string strAllData)
        {
            var WindDataStation = new WindData();
            try
            {
                if (strAllData == "Error") throw new NullReferenceException();
                string[] arrAll = strAllData.Split('=');
                // get date
                string[] arrTmp = arrAll[1].Split('&');
                string tmpDate = arrTmp[0];

                arrTmp = arrAll[2].Split('&');
                Thread.CurrentThread.CurrentCulture = new CultureInfo("he-IL");
                DateTime dateTemp = Convert.ToDateTime(tmpDate + " " + arrTmp[0]);
                WindDataStation.StationTime = dateTemp;
                WindDataStation.StationAdjustedTime = dateTemp.AddHours(intAddHour);
                WindDataStation.CreatedOnUtc = dateTemp;

                // speed
                arrTmp = arrAll[3].Split('&');
                double temp = Convert.ToDouble(arrTmp[0]);
                WindDataStation.WindSpeed = Convert.ToInt32(temp);
                WindDataStation.WindGust = Convert.ToInt32(Convert.ToInt32(temp) * 1.2);
                WindDataStation.WindSpeedAgv = Convert.ToInt32(temp);
                // direction
                arrTmp = arrAll[4].Split('&');
                WindDataStation.WindDirection = Convert.ToInt32(Convert.ToDouble(arrTmp[0]));
                // temp
                arrTmp = arrAll[5].Split('&');
                WindDataStation.Temperture = Convert.ToDouble(arrTmp[0]);
                // barometer
                arrTmp = arrAll[6].Split('&');
                WindDataStation.Barometer = Convert.ToDouble(arrTmp[0]);
                WindDataStation.Humidity = 0; WindDataStation.CloudBase = 0; WindDataStation.DewPoint = 0;

            }
            catch (Exception ex)
            {
                string t = ex.Message;
                WindDataStation.StationTime = Convert.ToDateTime("1/1/12 00:00");
                WindDataStation.StationAdjustedTime = WindDataStation.StationTime;
                WindDataStation.WindSpeed = 0;
                WindDataStation.WindGust = 0;
                WindDataStation.WindSpeedAgv = 0;
                WindDataStation.WindDirection  = 0;
                return WindDataStation;
            }
            return WindDataStation;
        }

        private WindData SplitWindDetailsPage(int intAddHour, string strAllData)
        {
            var WindDataStation = new WindData();
            try
            {
                //WebClient webClient = new WebClient();
                //string page = webClient.DownloadString(strAllData);

                HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
                doc.LoadHtml(strAllData);

                List<List<string>> table = doc.DocumentNode.SelectSingleNode("//table")
                            .Descendants("tr")
                            .Skip(1)
                            .Where(tr => tr.Elements("td").Count() > 1)
                            .Select(tr => tr.Elements("td").Select(td => td.InnerText.Trim()).ToList())
                            .ToList();

                //Date and Time
                string[] DateTimeCell = Regex.Split(table[1][0], "\r\n");
                string[] DateTimeString = Regex.Split(DateTimeCell[1], "on");
                Thread.CurrentThread.CurrentCulture = new CultureInfo("he-IL");
                DateTime dateTemp = Convert.ToDateTime(DateTimeString[0] + " " + DateTimeString[1]);
                WindDataStation.StationTime = dateTemp;
                WindDataStation.StationAdjustedTime = dateTemp.AddHours(intAddHour);
                WindDataStation.CreatedOnUtc = dateTemp;

                // speed
                WindDataStation.WindSpeed = Convert.ToInt32(table[4][1]);
                WindDataStation.WindGust = Convert.ToInt32(table[5][1]);
                WindDataStation.WindSpeedAgv = Convert.ToInt32(table[4][6]);
                // direction
                WindDataStation.WindDirection = Convert.ToInt32(table[3][2]);
                // temp
                WindDataStation.Temperture = Convert.ToDouble(table[9][1]);
                // barometer
                WindDataStation.Barometer = Convert.ToDouble(table[10][1]);
                WindDataStation.Humidity = 0; WindDataStation.CloudBase = 0; WindDataStation.DewPoint = 0;

            }
            catch (Exception ex)
            {
                string t = ex.Message;
            }
            return WindDataStation;
        }
        #endregion

    }
}
